/**
 * Promise A+ 原生promise
 * @params exector[function]
 * @return promise实例
 * by wangyuyuan
 * 
*/
(function () {
    function Promise(exector) {
        var self = this,
            change;

        if(!(self instanceof Promise)) throw new TypeError('undefined is not a Promise');
        if(typeof exector !== 'function') throw new TypeError(exector+'is not a function');

        self.state = 'pending';
        self.result = undefined;
        self.onFulfilledCallbacks = [];
        self.onRejectedCallbacks = [];

        change = function change(state,result) {
            if(self.state !== 'pending') return;
            self.state = state;
            self.result = result;
            // 非立即执行
            var arr = state === 'fulfilled' ? self.onRejectedCallbacks :self.onRejectedCallbacks,
                i = 0,
                len = arr.length,
                callback;
            if(arr.length>0){
                setTimeout(function(){
                    for(;i<len;i++){
                        callback = arr[i];
                        if(typeof callback === 'function') callback(result);
                    }
                },0)
            }
        }

        try {
            exector(function resolve(result) {
                change('fulfilled',result)
            },function reject(reason) {
                change('rejected',reason)
            })
        } catch (err) {
            change('rejected',err)
        }
    }

    // 是否为promise
    function isPromise(x) {
        if(x == null) return false;
        if(/^(object|function)$/i.test(typeof x)){
            if(typeof x.then === 'function'){
                return true;
            }
        }
        return false;
    }

    // 返回数据的处理
    function handle(newPromise,x,resolve,reject) {
        if(newPromise === x) throw new TypeError('error');
        if(isPromise(x)){
            try {
                x.then(resolve,reject);
            } catch (err) {
                reject(err);
            }
            return;
        }
        resolve(x);
    }

    // 原型上的方法
    Promise.prototype = {
        constructor : Promise,
        self : true,
        then : function (onFulfilled,onRejected) {
            var self = this,
                newPromise,
                x;
            // 处理穿透
            if(typeof onFulfilled !== 'function'){
                onFulfilled = function onFulfilled(result) {
                    return result;
                }
            }
            if(typeof onRejected !== 'function'){
                onRejected = function onRejected(reason) {
                    throw reason;
                }
            }
            
            newPromise = new Promise(function (resolve,reject) {
                switch (self.state) {
                    case 'fulfilled':
                        setTimeout(function(){
                            try {
                                x = onFulfilled(self.result);
                                handle(newPromise,x,resolve,reject);
                            } catch (err) {
                                reject(err)
                            }
                        },0)
                        break;
                    case 'rejected':
                        setTimeout(function(){
                            try {
                                x = onRejected(self.result);
                                handle(newPromise,x,resolve,reject);
                            } catch (err) {
                                reject(err)
                            }
                        },0)
                        break;
                    default:
                        self.onFulfilledCallbacks.push(function resolve(result) {
                            try {
                                x = onFulfilled(result);
                                handle(newPromise,x,resolve,reject);
                            } catch (err) {
                                reject(err)
                            }
                        });
                        self.onRejectedCallbacks.push(function reject(reason) {
                            try {
                                x = onRejected(reason);
                                handle(newPromise,x,resolve,reject);
                            } catch (err) {
                                reject(err)
                            }
                        });
                }
            });
            return newPromise;
           
        },
        catch : function (onRejected) {
            return this.then(null,onRejected);
        }
    }
    if(typeof Symbol !== 'undefined') Promise.prototype[Symbol.toStringTag] = "Promise";

    Promise.resolve = function resolve(result) {
        return new Promise(function (resolve) {
            resolve(result);
        })
    };
    Promise.rejected = function rejected(reason) {
        return new Promise(function (_,reject){
            reject(reason)
        })
    };
    Promise.all = function all(promises) {
        var newPromise,
            n = 0,
            results = [];

        if(!Array.isArray(promises)) throw new TypeError(promises+'must be iterator');
        promises = promises.map(function(item){
            if(!isPromise(item)){
                return Promise.resolve(item);
            };
            return item;
        })
        
        newPromise = new Promise(function(resolve,reject){
            promises.forEach(function(promise,index){
                promise.then(function resolve(result){
                    n++;
                    results[index] = result;

                    if(n >= promises.length){
                        return resolve(results);
                    }
                }).catch(function reject(reason){
                    return reject(reason)
                })
            });
        });

        return newPromise;
    };

    if(typeof window !== 'undefined') window.Promise = Promise;
})();